#include "StdAfx.h"
#include "DiskIoAssistant.h"

using namespace Adaptive::Foundation::IO;

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods
// <summary>
// Initializes a new instance of the class.
// </summary>
// <remarks>
// This constructor is hidden to prevent instantiation.
// </remarks>
DiskIoAssistant::DiskIoAssistant()
{
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Methods / Functions
 *------------------------------------------------------------------------------*/
#pragma region Public Methods / Functions
// Closes the supplied open handle.
void DiskIoAssistant::Close(IntPtr handle)
{
	HANDLE handleValue = NULL;

	if (handle != IntPtr::Zero)
	{
		handleValue = (HANDLE)(handle.ToPointer());
		::CloseHandle(handleValue);
	}
}
// Closes the supplied open handle.
void DiskIoAssistant::Close(SafeHandle^ handle)
{
	if (handle != nullptr)
		handle->Close();
}
// Opens a handle to the specified device.
SafeFileHandle^ DiskIoAssistant::OpenVolume(String^ deviceName)
{
	HANDLE fileHandle = NULL;
	SafeFileHandle^ returnValue = nullptr;			//Return value.
	CString wideName = "\\\\.\\" + deviceName + ":";		//Unmanaged name.

	fileHandle = ::CreateFile(wideName, GENERIC_READ | GENERIC_WRITE,
								FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
								NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
	if (fileHandle == NULL)
		throw gcnew IOException("Could not open volume handle.", gcnew Win32Exception(GetLastError()));
	else
	{
		returnValue = gcnew SafeFileHandle(IntPtr::IntPtr(fileHandle), true);
	}
	return returnValue;
}
// Opens a handle to the specified file.
SafeFileHandle^ DiskIoAssistant::OpenFile(String^ path)
{
	HANDLE fileHandle = NULL;
	SafeFileHandle^ returnValue = nullptr;			//Return value.
	CString wideName = path;						//Unmanaged name.

	fileHandle = ::CreateFile(wideName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
								NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

	if (fileHandle == NULL)
		throw gcnew IOException("Could not open file.", gcnew Win32Exception(GetLastError()));
	else
	{
		returnValue = gcnew SafeFileHandle(IntPtr::IntPtr(fileHandle), true);
	}
	return returnValue;
}
// Get cluster usage for a device
BitArray^ DiskIoAssistant::GetVolumeMap(String^ deviceName)
{
	SafeFileHandle^ volumeHandle = nullptr;
	HANDLE heapHandle = NULL;
	size_t size = 67108864;
	LPVOID memoryLocation = NULL;
	DWORD bytesReturned = 0;
	BOOL result = FALSE;
	VOLUME_BITMAP_BUFFER* bitmapBuffer = NULL;
	BYTE* dataContent = NULL;
	BitArray^ returnValue = nullptr;
	__int64 data = 0;

	try
	{
		//Open a handle to the volume.
		volumeHandle = OpenVolume(deviceName);
		if (volumeHandle != nullptr)
		{
			//Allocate a buffer on the heap.
			heapHandle = GetProcessHeap();
			memoryLocation = HeapAlloc(heapHandle, 0, size);

			result = ::DeviceIoControl((HANDLE)volumeHandle->DangerousGetHandle().ToPointer(), FSCTL_GET_VOLUME_BITMAP, 
								(LPVOID)&data, sizeof(__int64), memoryLocation, size, &bytesReturned, NULL);
			if (result)
			{
				bitmapBuffer = (VOLUME_BITMAP_BUFFER*)memoryLocation;
				dataContent = new BYTE[(int)bitmapBuffer->BitmapSize.QuadPart];
				memset(dataContent, 0, (size_t)bitmapBuffer->BitmapSize.QuadPart);
				memcpy(dataContent, bitmapBuffer->Buffer, (size_t)bitmapBuffer->BitmapSize.QuadPart);
				bitmapBuffer = NULL;

				array<Byte>^ conv = gcnew array<Byte>((size_t)bitmapBuffer->BitmapSize.QuadPart);
				for(int count = 0; count < (int)bitmapBuffer->BitmapSize.QuadPart; count++)
					conv[count] = dataContent[count];

				returnValue = gcnew BitArray( conv );
				delete(conv);
				delete(dataContent);
			}

			//Clear the heap.
			HeapFree(heapHandle, 0, memoryLocation);
			memoryLocation = NULL;
			heapHandle = NULL;


		}
	}
	catch(...)
	{
	}
	
	return returnValue;
}
// move a virtual cluster for a file to a logical cluster on disk, repeat for count clusters
void DiskIoAssistant::MoveFile(String^ deviceName, String^ path, __int64 numberOfClusterToBeMoved,
								__int64 diskClusterToMoveTo, int numberOfClustersToMove)
{
	SafeFileHandle^ volumeHandle = nullptr;
	SafeFileHandle^ fileHandle = nullptr;
	MOVEFILE_DESCRIPTOR* moveFileData = NULL;
	size_t bufferSize = 0;
	DWORD bytesReturned = 0;
	BOOL result = FALSE;

	volumeHandle = OpenVolume(deviceName);
	if (volumeHandle != nullptr)
	{
		fileHandle = OpenFile(path);
		if (fileHandle != nullptr)
		{
			moveFileData = new MOVEFILE_DESCRIPTOR();
			moveFileData->fileHandle = (HANDLE)fileHandle->DangerousGetHandle().ToPointer();
			moveFileData->StartingVCN = (ULONGLONG)numberOfClusterToBeMoved;
			moveFileData->StartingLCN = (ULONGLONG)diskClusterToMoveTo;
			moveFileData->ClusterCount = (__int64)numberOfClustersToMove;
			bufferSize = sizeof(MOVEFILE_DESCRIPTOR);

			result = ::DeviceIoControl(
									(HANDLE)volumeHandle->DangerousGetHandle().ToPointer(),
									FSCTL_MOVE_FILE, moveFileData, bufferSize, NULL, 0, &bytesReturned, NULL);

			delete(moveFileData);
			fileHandle->Close();
		}
		volumeHandle->Close();
	}
}
// Finds last large block of free space on the drive.
int DiskIoAssistant::FindLastOpenBlockStart(String^ drive)
{
	BitArray^ bits = GetVolumeMap(drive);
	int length = 0;

	length = bits->Length - 1;
	do
	{
		length--;
	} while (!bits[length]);

	delete(bits);
	return length + 4;
}

// Gets the list of free space blocks on the specified drive.
FreeSpaceBlockCollection^ DiskIoAssistant::GetFreeSpaceBlocks(String^ deviceName)
{
	FreeSpaceBlockCollection^ returnValue = nullptr;
	FreeSpaceBlock^ newEntry = nullptr;
	BitArray^ driveMap = nullptr;
	int length = 0;
	int count = 0;

	returnValue = gcnew FreeSpaceBlockCollection();
	driveMap = GetVolumeMap(deviceName);
	length = driveMap->Length;
	do
	{
		do
		{
			count++;
		} while ((count < length) && (driveMap[count]));

		if (count < length)
		{
			newEntry = gcnew FreeSpaceBlock();
			newEntry->StartCluster = count;
			do
			{
				count++;
			} while ((count < length) && (driveMap[count]));
			count--;

			newEntry->ClusterSize = count - newEntry->StartCluster;
			if (newEntry->ClusterSize > 1)
				returnValue->Add(newEntry);
		}
		newEntry = nullptr;

	} while (count < length);

	return returnValue;
}
// Gets the size of a cluster on the specified drive.
__int64	DiskIoAssistant::GetDriveClusterSize(String^ driveLetter)
{
	if ((driveLetter != nullptr) && (driveLetter->Length > 0))
		return GetDriveClusterSize(driveLetter[0]);
	else
		return 0;
}
// Gets the size of a cluster on the specified drive.
__int64	DiskIoAssistant::GetDriveClusterSize(wchar_t driveLetter)
{
	DWORD sectorsPerCluster = 0;
	DWORD bytesPerSector = 0;
	DWORD numFreeClusters = 0;
	DWORD numClusters = 0;
	CString rootPath = L"";
	__int64 returnValue = 0;

	rootPath.AppendChar(driveLetter);
	rootPath.Append(L":\\");

	GetDiskFreeSpace(rootPath, &sectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters);
	
	returnValue = (__int64)(bytesPerSector * sectorsPerCluster);
	return returnValue;
}
// Gets the size of the specified file.
//
// Parameters:
//		fileName - The fully-qualified path and name of the file.
//
// Return Value:
//		A 64-bit integer indicating the size of the file, in bytes.
//
__int64	DiskIoAssistant::GetFileSizeInBytes(String^ fileName)
{
	HANDLE fileHandle = 0;
	LARGE_INTEGER size;
	__int64 returnValue = 0;
	CString wideName = fileName;

	fileHandle = CreateFile(wideName, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
							FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,
							NULL);

	if (fileHandle != NULL)
	{
		GetFileSizeEx(fileHandle, &size);
		returnValue = (__int64)size.QuadPart;
		CloseHandle(fileHandle);
	}
	return returnValue;
}
// Gets the cluster file mapping for the specified file.
FileClusterMapEntryCollection^ DiskIoAssistant::GetFileLocationData(String^ fileName)
{
	SafeFileHandle^					fileHandle = nullptr;
	BOOL							result = FALSE;
	const size_t					AllocationSize = 65536;
	ULONGLONG						input = 0;
	DWORD							bytesReturned = 0;
	HANDLE							heapHandle  = NULL;
	LPVOID							memoryContentLocation = NULL;
	RETRIEVAL_POINTERS_BUFFER*		buffer = NULL;
	int								extentCount = 0;
	int								count = 0;
	EXTENTS*						extentsPtr = NULL;
	FILEMAP*						returnData = NULL;
	FileClusterMapEntryCollection^  returnValue = nullptr;

	fileHandle = OpenFile(fileName);
	if (fileHandle != nullptr)
	{
		//Allocate memory for storage.
		heapHandle = GetProcessHeap();
		if (heapHandle != NULL)
		{
			memoryContentLocation = HeapAlloc(heapHandle, HEAP_ZERO_MEMORY, AllocationSize);
			if (memoryContentLocation != NULL)
			{
				result = DeviceIoControl((HANDLE)fileHandle->DangerousGetHandle().ToPointer(), FSCTL_GET_RETRIEVAL_POINTERS, &input, sizeof(input), 
										 memoryContentLocation, AllocationSize, &bytesReturned, NULL);

				if (result == TRUE)
				{
					buffer = (RETRIEVAL_POINTERS_BUFFER*)memoryContentLocation;
					extentCount = buffer->ExtentCount;
					returnData = new FILEMAP[extentCount];
					extentsPtr = (EXTENTS*)buffer->Extents;

					for (count = 0; count < extentCount; count++)
					{
						returnData[count].Lcn = (__int64)extentsPtr->Lcn.QuadPart;
						returnData[count].NextVcn = (__int64)extentsPtr->NextVcn.QuadPart;
						extentsPtr++;
					}
				}
				HeapFree(heapHandle, 0, memoryContentLocation);
				heapHandle = NULL;
			}
		}
		fileHandle->Close();
		delete(fileHandle);
	}
	fileHandle = nullptr;
	return returnValue;
}
__int64	DiskIoAssistant::GetFileLocationDataSize(String^ fileName)
{
	SafeFileHandle^	fileHandle =  nullptr;
	HANDLE	heapHandle = NULL;
	LPVOID	memoryContentLocation = NULL;
	RETRIEVAL_POINTERS_BUFFER*	buffer = NULL;
	BOOL	result = FALSE;
	const size_t					AllocationSize = 65536;
	ULONGLONG						input = 0;
	DWORD							bytesReturned = 0;
	__int64 returnValue = 0;

	fileHandle = OpenFile(fileName);
	if (fileHandle != nullptr)
	{
		//Allocate memory for storage.
		heapHandle = GetProcessHeap();
		if (heapHandle != NULL)
		{
			memoryContentLocation = HeapAlloc(heapHandle, HEAP_ZERO_MEMORY, AllocationSize);
			if (memoryContentLocation != NULL)
			{
				result = DeviceIoControl((HANDLE)fileHandle->DangerousGetHandle(), FSCTL_GET_RETRIEVAL_POINTERS, &input, sizeof(input), 
										 memoryContentLocation, AllocationSize, &bytesReturned, NULL);

				if (result == TRUE)
				{
					buffer = (RETRIEVAL_POINTERS_BUFFER*)memoryContentLocation;
					returnValue = (buffer->ExtentCount * 8);
				}
			}
			HeapFree(heapHandle, 0, memoryContentLocation);
			heapHandle = NULL;
		}
		fileHandle->Close();
		delete(fileHandle);
	}
	fileHandle=nullptr;
	return returnValue;
}
__int64	DiskIoAssistant::GetFirstFreeSpace(String^ driveLetter, __int64 bytesRequired)
{
	if ((driveLetter != nullptr) && (driveLetter->Length > 0))
		return GetFirstFreeSpace(driveLetter[0], bytesRequired);
	else
		return 0;
}
__int64	DiskIoAssistant::GetFirstFreeSpace(wchar_t driveLetter, __int64 bytesRequired)
{
	__int64 returnValue = 0;
	array<Byte>^ volumeBitmap = nullptr;
	ULONGLONG bitsToFind = (bytesRequired / GetDriveClusterSize(driveLetter));
	ULONGLONG startPos = 0;
	ULONGLONG count = 0;
	ULONGLONG length = 0;

	length = GetVolumeBitmapSize(driveLetter);
	volumeBitmap = GetVolumeBitmap(driveLetter);

	if (volumeBitmap != nullptr)
	{
		do
		{
			//Find a free space.
			while (volumeBitmap[(int)startPos] > 0)
				startPos++;

			count = 0;
			do
			{
				count++;
			} while ((volumeBitmap[(int)(startPos + count)] == 0) && (count <= bitsToFind));
			
			if (count >= bitsToFind)
				returnValue = (__int64)startPos;
			else
				startPos++;

		} while ((count <= bitsToFind) && ((startPos + bitsToFind) < length));

		delete(volumeBitmap);
	}
	return returnValue;

}
__int64	DiskIoAssistant::GetLastFreeSpace(String^ driveLetter, __int64 bytesRequired)
{
	if ((driveLetter != nullptr) && (driveLetter->Length > 0))
		return GetLastFreeSpace(driveLetter[0], bytesRequired);
	else
		return 0;
}
__int64 DiskIoAssistant::GetLastFreeSpace(wchar_t driveLetter, __int64 bytesRequired)
{
	__int64 returnValue = 0;
	array<Byte>^ volumeBitmap = nullptr;
	ULONGLONG bitsToFind = (bytesRequired / GetDriveClusterSize(driveLetter));
	ULONGLONG startPos = 0;
	ULONGLONG count = 0;
	ULONGLONG length = 0;

	length = GetVolumeBitmapSize(driveLetter);
	volumeBitmap = GetVolumeBitmap(driveLetter);

	if (volumeBitmap != nullptr)
	{
		startPos = length - 1;
		do
		{
			//Find a free space.
			while (volumeBitmap[(int)startPos] > 0)
				startPos--;

			count = 0;
			do
			{
				count++;
			} while ((volumeBitmap[(int)(startPos - count)] == 0) && (count <= bitsToFind));
			
			if (count >= bitsToFind)
				returnValue = (__int64)startPos;
			else
				startPos--;

		} while ((count <= bitsToFind) && ((startPos + bitsToFind) < length));

		delete(volumeBitmap);
	}
	return returnValue;
}
// Gets the size of the volume bitmap byte array, in bytes.
//
// Parameters:
//		driveLetter - The letter of the drive to be examined.
//
// Return Value:
//		The number of bytes required to store the volume bitmap byte array.
//
int	DiskIoAssistant::GetVolumeBitmapSize(String^ driveLetter)
{
	if ((driveLetter != nullptr) && (driveLetter->Length > 0))
		return GetVolumeBitmapSize(driveLetter[0]);
	else
		return 0;
}
int DiskIoAssistant::GetVolumeBitmapSize(wchar_t driveLetter)
{
	DWORD	sectorsPerCluster = 0;
	DWORD	bytesPerSector = 0;
	DWORD	numFreeClusters = 0;
	DWORD	numClusters = 0;
	CString rootPath = L"";
	int returnValue = 0;

	//Append the name.
	rootPath.AppendChar(driveLetter);
	rootPath.Append(L":\\");

	GetDiskFreeSpace(rootPath, &sectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters);
	returnValue = (int)numClusters;
	return returnValue;
}

// Gets the current volume bitmap.
//
// Parameters:
//		driveLetter - The letter of the drive to be examined.
//
// Return Value:
//		A byte array representing the cluster usage on the specified drive.
//
array<Byte>^ DiskIoAssistant::GetVolumeBitmap(String^ driveLetter)
{
	if ((driveLetter != nullptr) && (driveLetter->Length > 0))
		return GetVolumeBitmap(driveLetter[0]);
	else
		return nullptr;
}
array<Byte>^ DiskIoAssistant::GetVolumeBitmap(wchar_t driveLetter)
{
	SafeFileHandle^ volumeHandle = nullptr;
	HANDLE heapHandle = NULL;
	size_t size = 67108864;
	LPVOID memoryLocation = NULL;
	DWORD bytesReturned = 0;
	BOOL result = FALSE;
	VOLUME_BITMAP_BUFFER* bitmapBuffer = NULL;
	BYTE* dataContent = NULL;
	array<Byte>^ returnValue = nullptr;
	__int64 data = 0;
	
	try
	{
		//Open a handle to the volume.
		volumeHandle = OpenVolume( gcnew String( &driveLetter ));
		if (volumeHandle != nullptr)
		{
			//Allocate a buffer on the heap.
			heapHandle = GetProcessHeap();
			memoryLocation = HeapAlloc(heapHandle, 0, size);

			result = ::DeviceIoControl((HANDLE)volumeHandle->DangerousGetHandle().ToInt32(), FSCTL_GET_VOLUME_BITMAP, 
								(LPVOID)&data, sizeof(__int64), memoryLocation, size, &bytesReturned, NULL);
			if (result)
			{
				bitmapBuffer = (VOLUME_BITMAP_BUFFER*)memoryLocation;
				dataContent = new BYTE[(size_t)bitmapBuffer->BitmapSize.QuadPart];
				memset(dataContent, 0, (size_t)bitmapBuffer->BitmapSize.QuadPart);
				memcpy(dataContent, bitmapBuffer->Buffer, (size_t)bitmapBuffer->BitmapSize.QuadPart);

				returnValue = gcnew array<Byte>((int)bitmapBuffer->BitmapSize.QuadPart);
				for(int count = 0; count < bitmapBuffer->BitmapSize.QuadPart; count++)
					returnValue[count] = (Byte)dataContent[count];

				delete(dataContent);
			}

			//Clear the heap.
			HeapFree(heapHandle, 0, memoryLocation);
			memoryLocation = NULL;
			heapHandle = NULL;
		}
	}
	catch(...)
	{
	}
	
	return returnValue;
}
//
void DiskIoAssistant::MoveFileToFirstFreeSpace(String^ fileName)
{
	wchar_t driveLetter = fileName[0];
	ULONGLONG freeClusterNo = 0;
	FileClusterMapEntryCollection^ fileLocationData = nullptr;
	FileClusterMapEntry^ item = nullptr;
	SafeFileHandle^ volumeHandle = nullptr;
	SafeFileHandle^ fileHandle = nullptr;
	__int64 bytes = 0;
	int count = 0;
	int length = 0;
	int clusterCount = 0;
	BOOL result = FALSE;
	MOVEFILE_DESCRIPTOR desc;
	DWORD size = 0;
	LONGLONG startVcn = 0;
	__int64 fileClusters = 0;

	bytes = GetFileSizeInBytes(fileName);
	fileClusters = bytes / GetDriveClusterSize(fileName[0]);

	fileLocationData = GetFileLocationData(fileName);
	freeClusterNo = GetFirstFreeSpace(driveLetter, bytes);
	
	volumeHandle = OpenVolume(gcnew String( &driveLetter ));
	if (volumeHandle != nullptr)
	{
		count = 0;
		item = fileLocationData[count];
		do
		{
			length++;
			count++;
		} while (item->NextVirtualClusterNumber < fileClusters);

		fileHandle = OpenFile(fileName);
		if (fileHandle != nullptr)
		{
			startVcn = 0;
			for (count = 0; count < length; count++)
			{
				item = fileLocationData[count];
				desc.ClusterCount = item->NextVirtualClusterNumber - startVcn;
				desc.fileHandle = (HANDLE)fileHandle->DangerousGetHandle();
				desc.StartingLCN = freeClusterNo;
				desc.StartingVCN = startVcn;

				result = DeviceIoControl(
						(HANDLE)volumeHandle->DangerousGetHandle(),
						FSCTL_MOVE_FILE,
						&desc,
						sizeof(desc),
						NULL,
						0,
						&size,
						NULL);

				if (result == TRUE)
				{
					startVcn += clusterCount;
					freeClusterNo += clusterCount;
				}
				else
				{
					count = length;
				}
			}
			fileHandle->Close();
			delete(fileHandle);
		}
		volumeHandle->Close();
		delete(volumeHandle);
	}
}
void DiskIoAssistant::MoveFileToLastFreeSpace(String^ fileName)
{
	wchar_t driveLetter = fileName[0];
	ULONGLONG freeClusterNo = 0;
	FileClusterMapEntryCollection^ fileLocationData = nullptr;
	FileClusterMapEntry^ item = nullptr;
	__int64 bytes = 0;
	SafeFileHandle^ volumeHandle = nullptr;
	SafeFileHandle^ fileHandle = nullptr;
	int count = 0;
	int length = 0;
	int clusterCount = 0;
	BOOL result = FALSE;
	MOVEFILE_DESCRIPTOR desc;
	DWORD size = 0;
	LONGLONG startVcn = 0;
	ULONGLONG startLcn = 0;

	__int64 fileClusters = 0;

	bytes = GetFileSizeInBytes(fileName);
	fileClusters = bytes / GetDriveClusterSize(fileName[0]);

	fileLocationData = GetFileLocationData(fileName);
	freeClusterNo = GetLastFreeSpace(driveLetter, bytes);
	startLcn = freeClusterNo;

	volumeHandle = OpenVolume(gcnew String(&driveLetter));
	if (volumeHandle != nullptr)
	{
		count = 0;
		item = fileLocationData[count];
		do
		{
			item = fileLocationData[count];
			length++;
			count++;
		} while (item->NextVirtualClusterNumber < fileClusters);

		fileHandle = OpenFile(fileName);

		startVcn = 0;
		for (count = 0; count < length; count++)
		{
			item = fileLocationData[count];
			desc.ClusterCount = item->NextVirtualClusterNumber - startVcn;
			desc.fileHandle = (HANDLE)fileHandle->DangerousGetHandle();
			desc.StartingLCN = freeClusterNo;
			desc.StartingVCN = startVcn;

			result = DeviceIoControl(
                    (HANDLE)volumeHandle->DangerousGetHandle(),
                    FSCTL_MOVE_FILE,
                    &desc,
                    sizeof(desc),
                    NULL,
                    0,
                    &size,
                    NULL);

			if (result == TRUE)
			{
				startVcn += clusterCount;
				freeClusterNo += clusterCount;
			}
			else
			{
				count = length;
			}
		}
		
		if (!result)
		{
			for (count = 0; count < fileClusters; count++)
			{
				MoveSingleCluster(volumeHandle, fileHandle, (__int64)startLcn, (__int64)count);
				startLcn++;
			}
		}
		fileHandle->Close();
		delete(fileHandle);

		volumeHandle->Close();
		delete(volumeHandle);
	}
}
bool DiskIoAssistant::MoveSingleCluster(SafeFileHandle^ volumeHandle, SafeFileHandle^ fileHandle, __int64 logicalClusterNumber, 
								__int64 virtualClusterNumber)
{
	BOOL returnValue = FALSE;
	MOVEFILE_DESCRIPTOR operation;
	DWORD size = 0;

	//Set operation parameters.
	operation.ClusterCount = 1;
	operation.fileHandle = (HANDLE)fileHandle->DangerousGetHandle();
	operation.StartingLCN = logicalClusterNumber;
	operation.StartingVCN = virtualClusterNumber;

	returnValue = DeviceIoControl(
                    (HANDLE)volumeHandle->DangerousGetHandle(),
                    FSCTL_MOVE_FILE,
                    &operation,
                    sizeof(operation),
                    NULL,
                    0,
                    &size,
                    NULL);
	return (returnValue > 0);
}

bool DiskIoAssistant::MoveSingleCluster(IntPtr volumeHandle, IntPtr fileHandle, __int64 logicalClusterNumber, 
								__int64 virtualClusterNumber)
{
	BOOL returnValue = FALSE;
	MOVEFILE_DESCRIPTOR operation;
	DWORD size = 0;

	//Set operation parameters.
	operation.ClusterCount = 1;
	operation.fileHandle = (HANDLE)fileHandle.ToInt32();
	operation.StartingLCN = logicalClusterNumber;
	operation.StartingVCN = virtualClusterNumber;

	returnValue = DeviceIoControl(
                    (HANDLE)volumeHandle.ToInt32(),
                    FSCTL_MOVE_FILE,
                    &operation,
                    sizeof(operation),
                    NULL,
                    0,
                    &size,
                    NULL);
	return (returnValue > 0);
}

#pragma endregion
